/*
 * PhotonRTOS础光实时操作系统 -- counter 实现文件
 *
 * Copyright (C) 2022 国科础石(重庆)软件有限公司
 *
 * 作者: Lin Yang <s-yanglin@kernelsoft.com>
 *
 * License terms: GNU General Public License (GPL) version 3
 *
 */

#include <autosar/internal.h>

/******************************************************************
 *
 * [SWS_Os_00374]
 * ⌈操作系统模块应处理由操作系统模块直接使用
 * 而不由 GPT 驱动程序处理的所有定时器的初始化和配置。
 * ⌋ ( SRS_Frt_00020 )
 *
 * [SWS_Os_00384]
 * ⌈操作系统模块应调整硬件定时器（驱动计数器）的读出值，
 * 使最小值为零，连续读取返回递增的计数值，
 * 直到定时器达到定时器模数（允许的最大值+1）。
 *  ⌋ ( SRS_Frt_00030 , SRS_Frt_00031 )
 *
 * [SWS_Os_00630] ⌈不允许从分配给不同核心的 COUNTER 驱动调度表。 ⌋
 * ( SRS_Os_80013 )
 *
 * [SWS_Os_00631] ⌈不允许从分配给不同核心的 COUNTER 驱动 ALARM。 ⌋
 * ( SRS_Os_80013 )
 *
 *****************************************************************/

VAR(OsCounterType, AUTOMATIC)
	autosar_counters[AUTOSAR_NR_COUNTER];

VAR(OsWaiterType, AUTOMATIC)
	autosar_waiters[AUTOSAR_NR_WAITER];


/* 将一个等待者添加到计数器的实际实现 */
LOCAL_INLINE  FUNC(void, OS_CODE) __add_waiter_to_counter(
	VAR(OsWaiterRefType, AUTOMATIC) waiter_ref,
	VAR(CounterType, AUTOMATIC) CounterID)
{
	VAR(OsCounterRefType, AUTOMATIC) counter_ref
		= &autosar_counters[CounterID];
	VAR(OsListRefType, AUTOMATIC) curr
		= counter_ref->waiters_list.next;
	waiter_ref->counter = CounterID;
	while (curr != &(counter_ref->waiters_list) &&
		list_container(curr, OsWaiterType, list)->time < waiter_ref->time) {
		curr = curr->next;
	}
	while (curr != &(counter_ref->waiters_list) &&
		list_container(curr, OsWaiterType, list)->time == waiter_ref->time) {
		/* 如果该等待者已经存在于计数器中,就不必再添加了 */
		if (list_container(curr, OsWaiterType, list) == waiter_ref) {
			pr_warn("Waiter is in counter, please do not add again!\n");
			return;
		}
		curr = curr->next;
	}
	__list_insert(&(waiter_ref->list), curr->prev, curr);
	if (counter_ref->next_waiter == NULL) {
		counter_ref->next_waiter = waiter_ref;
	} else if ((waiter_ref->time < counter_ref->next_waiter->time)
		&& (waiter_ref->time > counter_ref->value)) {
		counter_ref->next_waiter = waiter_ref;
	} else if ((counter_ref->next_waiter->time < counter_ref->value)
		&& ((waiter_ref->time > counter_ref->value)
		|| (waiter_ref->time < counter_ref->next_waiter->time))) {
		counter_ref->next_waiter = waiter_ref;
	}
}

/* 将一个等待者添加到计数器的接口实现 */
FUNC(StatusType, OS_CODE) add_waiter_to_counter(
	VAR(OsWaiterRefType, AUTOMATIC) waiter_ref,
	VAR(CounterType, AUTOMATIC) CounterID)
{
	VAR(StatusType, AUTOMATIC) status = E_OK;
	VAR(uintptr_t, AUTOMATIC) flags;
#if defined(EXTENDED_STATUS)
	/**
	 * 在扩展模式下，检查传入参数是否过大
	 */
	if (CounterID >= AUTOSAR_NR_COUNTER) {
		status = E_OS_ID;
		goto out;
	}

	if ((waiter_ref->time > autosar_counters[CounterID].max_value) ||
		(waiter_ref->cycle > (autosar_counters[CounterID].max_value + 1))) {
		status = E_OS_VALUE;
		goto out;
	}
#endif

	smp_lock_irqsave(&(autosar_counters[CounterID].lock), flags);
	__add_waiter_to_counter(waiter_ref, CounterID);
	smp_unlock_irqrestore(&(autosar_counters[CounterID].lock), flags);

out:
	return status;
}


/* 将一个等待者从计数器中移除的实际实现 */
LOCAL_INLINE FUNC(StatusType, OS_CODE) __remove_waiter_from_counter(
	VAR(OsWaiterRefType, AUTOMATIC) waiter_ref,
	VAR(CounterType, AUTOMATIC) CounterID)
{
	VAR(StatusType, AUTOMATIC) status = E_OK;
	VAR(OsCounterRefType, AUTOMATIC) counter_ref
		= &autosar_counters[CounterID];
	VAR(OsListRefType, AUTOMATIC) curr
		= counter_ref->waiters_list.next;
	VAR(OsListRefType, AUTOMATIC) tmp_list
		= waiter_ref->list.next;

	if (waiter_ref->counter != CounterID) {
		status = E_OS_VALUE;
		goto out;
	} else {
		waiter_ref->counter = AUTOSAR_NR_COUNTER;
	}
	while (curr != &(counter_ref->waiters_list) &&
		curr != &(waiter_ref->list)) {
		curr = curr->next;
	}
	/* 如果没有从列表中找到 */
	if (curr == &(counter_ref->waiters_list)) {
		status = E_OS_VALUE;
		goto out;
	}
	list_del(&(waiter_ref->list));
	if (tmp_list == &(counter_ref->waiters_list)) {
		if (list_is_empty(&(counter_ref->waiters_list))) {
			counter_ref->next_waiter = NULL_PTR;
		} else {
			counter_ref->next_waiter = list_container(counter_ref->waiters_list.next,
				OsWaiterType, list);
		}
	}

out:
	return status;
}

/* 将一个等待者从计数器中移除的接口实现 */
FUNC(StatusType, OS_CODE) remove_waiter_from_counter(
	VAR(OsWaiterRefType, AUTOMATIC) waiter_ref,
	VAR(CounterType, AUTOMATIC) CounterID)
{
	VAR(StatusType, AUTOMATIC) status = E_OK;
	VAR(uintptr_t, AUTOMATIC) flags;

#if defined(EXTENDED_STATUS)
	/**
	 * 在扩展模式下，检查传入参数是否过大
	 */
	if (CounterID >= AUTOSAR_NR_COUNTER) {
		status = E_OS_ID;
		goto out;
	}
#endif

	smp_lock_irqsave(&(autosar_counters[CounterID].lock), flags);
	__remove_waiter_from_counter(waiter_ref, CounterID);
	smp_unlock_irqrestore(&(autosar_counters[CounterID].lock), flags);

out:
	return status;
}


/* 将需要唤醒的等待者全部移除到list中 */
LOCAL_INLINE FUNC(void, OS_CODE) __remove_same_time_waiters(
	VAR(CounterType, AUTOMATIC) CounterID,
	VAR(OsListRefType, AUTOMATIC) list)
{
	VAR(OsCounterRefType, AUTOMATIC) counter_ref
		= &autosar_counters[CounterID];
	VAR(OsWaiterRefType, AUTOMATIC) waiter_ref
		= counter_ref->next_waiter;
	VAR(TickType, AUTOMATIC) when = waiter_ref->time;
	VAR(OsListRefType, AUTOMATIC) curr = counter_ref->waiters_list.next;
	VAR(OsListRefType, AUTOMATIC) tmp_next;
	while (curr != &(counter_ref->waiters_list) &&
		list_container(curr, OsWaiterType, list)->time == when) {
		tmp_next = curr->next;
		list_del(curr);
		list_insert_behind(curr, list);
		curr = tmp_next;
	}
	if (list_is_empty(&(counter_ref->waiters_list))) {
		counter_ref->next_waiter = NULL;
	} else {
		counter_ref->next_waiter
			= list_container(counter_ref->waiters_list.next,
			OsWaiterType, list);
	}
}

/* 唤醒相同时间的需要唤醒的等待者 */
FUNC(void, OS_CODE) __awake_same_time_waiters(
	VAR(CounterType, AUTOMATIC) CounterID)
{
	VAR(OsWaiterRefType, AUTOMATIC) waiter_ref;
	VAR(OsListType, AUTOMATIC) list;
	VAR(OsListRefType, AUTOMATIC) curr;
	VAR(OsListRefType, AUTOMATIC) tmp;
	VAR(OsCounterRefType, AUTOMATIC) counter_ref
		= &autosar_counters[CounterID];

	list_init(&list);
	__remove_same_time_waiters(CounterID, &list);
	list_for_each_safe(curr, tmp, &list) {
		list_del(curr);
		waiter_ref = list_container(curr, OsWaiterType, list);
		if (waiter_ref->cycle != 0) {
			waiter_ref->time += waiter_ref->cycle;
			if (waiter_ref->time > counter_ref->max_value) {
				waiter_ref->time -= (counter_ref->max_value + 1);
			}
			__add_waiter_to_counter(waiter_ref, CounterID);
		}
		smp_unlock(&(counter_ref->lock));
		if (waiter_ref->callback != NULL) {
			waiter_ref->callback(waiter_ref);
		} else {
			pr_warn("callback of waiter is NULL\n");
		}
		smp_lock(&(counter_ref->lock));
	}
}


/* 根据waiter指针获取waiter id，
 * 返回 AUTOSAR_NR_WAITER 表示指针无效 */
FUNC(OsWaiterIdType, OS_CODE) get_waiter_id(
	VAR(OsWaiterRefType, AUTOMATIC) waiter_ref)
{
	VAR(uintptr_t, AUTOMATIC) index = 0;

	index = (((uintptr_t)waiter_ref - (uintptr_t)autosar_waiters) / sizeof(OsWaiterType));
	if (index > AUTOSAR_NR_WAITER) {
		index = AUTOSAR_NR_WAITER;
	}

	return (OsWaiterIdType)index;
}


FUNC(StatusType, OS_CODE) IncrementHardwareCounter(
	VAR(CounterType, AUTOMATIC) CounterID)
{
	VAR(StatusType, AUTOMATIC) status;
	VAR(uintptr_t, AUTOMATIC) flags;

	if (CounterID >= AUTOSAR_NR_COUNTER) {
		status = E_OS_ID;
		goto out;
	}

	if (autosar_counters[CounterID].type == SOFTWARE) {
		status = E_OS_ID;
		goto out;
	}
	smp_lock_irqsave(&(autosar_counters[CounterID].lock), flags);
	status = __increment_counter(CounterID);
	smp_unlock_irqrestore(&(autosar_counters[CounterID].lock), flags);

out:
	return status;
}


LOCAL_INLINE FUNC(StatusType, OS_CODE) __get_counter_value(
	VAR(CounterType, AUTOMATIC) CounterID,
	VAR(TickRefType, AUTOMATIC) Value)
{
	*Value = ACCESS_ONCE(autosar_counters[CounterID].value);

	return E_OK;
}

/*
 * 语法
 * StatusType GetCounterValue (
 *      CounterType CounterID,
 *      TickRefType Value
 * )
 *
 * 服务 ID [hex]
 *      0x10
 *
 * 同步/异步
 *      同步（Synchronous）
 *
 * 可重入性
 *      可重入
 *
 * 参数 (in)
 *      CounterID
 *      应读取计数值的计数器
 *
 * 参数 (inout)
 *      None
 *
 * 参数 (out)
 *      Value
 *      包含计数器的当前计数值
 *
 * 返回值
 *      StatusType
 *      E_OK：没有错误
 *      E_OS_ID（仅处于 EXTENDED 状态）：<CounterID> 不是有效的
 *
 * 描述
 *      此服务读取计数器的当前计数值（如果计数器由硬件驱动，则返回硬
 * 件计时器tick，或者当用户驱动计数器时返回软件tick）。
 *
 * 引用
 *      AUTOSAR OS 8.4.18 GetCounterValue [SWS_Os_00383]
 */
FUNC(StatusType, OS_CODE) GetCounterValue(
	VAR(CounterType, AUTOMATIC) CounterID,
	VAR(TickRefType, AUTOMATIC) Value)
{
	VAR(StatusType, AUTOMATIC) status;

	CONTEXT_CHECK(ENV_TASK | ENV_CAT2_ISR)

#if defined(EXTENDED_STATUS)
	/**
	 * 在扩展模式下，检查传入参数是否过大
	 *
	 * [SWS_Os_00376]
	 * ⌈如果GetCounterValue ()调用中的输入参数
	 *  <CounterID>无效，
	 * 则GetCounterValue () 应返回E_OS_ID 。 ⌋ ( )
	 *
	 * [SWS_Os_00377]
	 * ⌈如果GetCounterValue ()调用中的
	 * 输入参数 <CounterID>有效，
	 * GetCounterValue()将通过 <Value> 返回计数器
	 * 的当前刻度值并返回E_OK 。 ⌋ ( SRS_Frt_00033 )
	 */
	if (CounterID >= AUTOSAR_NR_COUNTER) {
		status = E_OS_ID;
		goto out;
	}

	/**
	 * 在拓展模式下，检查传入的引用是否为 NULL
	 *
	 * [SWS_Os_00566]
	 * ⌈操作系统 API 应在扩展模式下检查所有指针参数
	 * 是否为NULL指针，如果此类参数为NULL ，
	 * 则以扩展状态返回E_OS_PARAM_POINTER 。 ⌋ ( )
	 */
	if (Value == NULL) {
		status = E_OS_PARAM_POINTER;
		goto out;
	}
#endif

	/********************************
	 * [SWS_Os_00531]
	 * ⌈ GetCounterValue ()的注意事项：
	 * 请注意，对于CounterType = HARDWARE的计数器，
	 * 返回的是实际计时器值
	 * （可能已调整的硬件值，请参阅SWS_Os_00384 ），
	 * 而对于CounterType = SOFTWARE的计数器，
	 * 则返回当前的“软件”刻度返回值。 ⌋ ( )
	 *
	 * [SWS_Os_00532]
	 * ⌈ GetCounterValue ()的可用性：
	 * 可用于所有可扩展性类。 ⌋ ( )
	 **********************************/

	status = __get_counter_value(CounterID, Value);

out:
	return status;
}

/* 递增一个计数器的实际实现 */
FUNC(StatusType, OS_CODE) __increment_counter(
	VAR(CounterType, AUTOMATIC) CounterID)
{
	VAR(TickType, AUTOMATIC) tmp_tick;
	VAR(TickType, AUTOMATIC) tmp_value;
	VAR(OsCounterRefType, AUTOMATIC) counter_ref
		= &autosar_counters[CounterID];

	tmp_tick = counter_ref->tick + 1;
	if (tmp_tick >= counter_ref->ticks_per_base) {
		tmp_tick = 0;
		counter_ref->tick = tmp_tick;

		tmp_value = counter_ref->value + 1;
		if (tmp_value > counter_ref->max_value) {
			tmp_value = 0;
		}
		counter_ref->value = tmp_value;

		if (counter_ref->next_waiter != NULL
			&& counter_ref->next_waiter->time == counter_ref->value) {
			__awake_same_time_waiters(CounterID);
		}
	} else {
		counter_ref->tick = tmp_tick;
	}

	return E_OK;
}

/*
 * 语法
 * StatusType IncrementCounter (
 *      CounterType CounterID
 * )
 *
 * 服务 ID [hex]
 *      0x0f
 *
 * 同步/异步
 *      同步, 可能会导致重新调度
 *
 * 可重入性
 *      可重入
 *
 * 参数 (in)
 *      CounterID
 *      要递增的计数器
 *
 * 参数 (inout)
 *      None
 *
 * 参数 (out)
 *      None
 *
 * 返回值
 *      StatusType
 *      E_OK：没有错误
 *      E_OS_ID（仅在 EXTENDED 状态下）：CounterID 无效或计数器在硬件中实现且
 * 不能由软件递增
 *
 * 描述
 *      该服务递增一个软件计数器的值。
 *
 * 引用
 *      AUTOSAR OS 8.4.17 IncrementCounter [SWS_Os_00399]
 */
FUNC(StatusType, OS_CODE) IncrementCounter(
	VAR(CounterType, AUTOMATIC) CounterID)
{
	VAR(StatusType, AUTOMATIC) status;
	VAR(uintptr_t, AUTOMATIC) flags;

#if defined(AUTOSAR_OS_APPLICATION)
	VAR(ApplicationType, AUTOMATIC) app_id;
	VAR(ApplicationType, AUTOMATIC) trusted_func_app_id;
	P2VAR(struct process_desc, AUTOMATIC, OS_APPL_DATA) pro_desc = current_proc_info();
#endif

	CONTEXT_CHECK(ENV_TASK | ENV_CAT2_ISR)

#if defined(AUTOSAR_OS_APPLICATION)
	trusted_func_app_id = pro_desc->object.trusted_func_app_id;
	app_id = trusted_func_app_id != INVALID_OSAPPLICATION
		? trusted_func_app_id : GetApplicationID();
#endif /* defined(AUTOSAR_OS_APPLICATION) */

#if defined(EXTENDED_STATUS)
	/**
	 * 在扩展模式下，检查传入参数是否过大
	 *
	 * [SWS_Os_00285] ⌈如果IncrementCounter ()调用中的输入参数
	 *  <CounterID>无效或计数器是硬件计数器，
	 * 则IncrementCounter()应返回E_OS_ID 。 ⌋ ( )
	 *
	 * [SWS_Os_00286] ⌈如果IncrementCounter ()的输入参数有效，
	 * 则IncrementCounter()应将计数器 <CounterID> 加一
	 * （如果连接到此计数器的任何闹钟到期，则完成给定的操作，
	 * 例如任务激活）并应返回E_OK 。 ⌋ ( SRS_Os_11020 )
	 */
	if (CounterID >= AUTOSAR_NR_COUNTER) {
		status = E_OS_ID;
		goto out;
	}

	if (autosar_counters[CounterID].type == HARDWARE) {
		status = E_OS_ID;
		goto out;
	}

#if defined(AUTOSAR_OS_APPLICATION)
	if (CheckObjectAccess(app_id, TYPE_COUNTER,
		&autosar_counters[CounterID].object) != ACCESS) {
		status = E_OS_ID;
		goto out;
	}
#endif
#endif

	/********************************************************
	 * [SWS_Os_00321]
	 * ⌈如果在调用IncrementCounter () 的过程中发生错误，
	 * 例如由于任务激活导致的E_OS_LIMIT ，
	 * 则IncrementCounter () 应调用错误钩子，
	 * 但IncrementCounter()服务本身应返回E_OK 。 ⌋ ( )
	 *
	 * [SWS_Os_00529]
	 * ⌈ IncrementCounter ()的注意事项：
	 * 如果从任务中调用，可能会发生重新调度。 ⌋ ( )
	 *
	 * [SWS_Os_00530]
	 * ⌈ IncrementCounter ()的可用性：
	 * 可用于所有可扩展性类。 ⌋ ( )
	 ********************************************************/

	/**
	 * [SWS_Os_00629]
	 * ⌈属于 OS-Application 的 COUNTER 应
	 * 由 OS-Application 所在的核心递增。
	 *  COUNTER 不应被其他核心递增。 ⌋ ( SRS_Os_80013 )
	 */
	if (GetCoreID() != autosar_counters[CounterID].core) {
		status = E_OS_ACCESS;
		goto out;
	}
	smp_lock_irqsave(&(autosar_counters[CounterID].lock), flags);
	status = __increment_counter(CounterID);
	smp_unlock_irqrestore(&(autosar_counters[CounterID].lock), flags);
out:
	return status;
}

LOCAL_INLINE FUNC(StatusType, OS_CODE) __get_elapsed_value(
	VAR(CounterType, AUTOMATIC) CounterID,
	VAR(TickRefType, AUTOMATIC) Value,
	VAR(TickRefType, AUTOMATIC) ElapsedValue)
{
	TickType new_value = ACCESS_ONCE(autosar_counters[CounterID].value);

	*ElapsedValue = new_value - *Value;
	*Value = new_value;

	return E_OK;
}

/*
 * 语法
 * StatusType GetElapsedValue (
 *      CounterType CounterID,
 *      TickRefType Value,
 *      TickRefType ElapsedValue
 * )
 *
 * 服务 ID [hex]
 *      0x11
 *
 * 同步/异步
 *      同步（Synchronous）
 *
 * 可重入性
 *      可重入
 *
 * 参数 (in)
 *      CounterID
 *      要读取的计数器
 *
 * 参数 (inout)
 *      Value
 *      in：之前读取的计数器的刻度值
 *      out：计数器的当前刻度值
 *
 * 参数 (out)
 *      ElapsedValue
 *      与上一次读取值的差异
 *
 * 返回值
 *      StatusType
 *      E_OK：没有错误
 *      E_OS_ID :（仅处于 EXTENDED 状态）：CounterID 无效
 *      E_OS_VALUE :（仅处于 EXTENDED 状态）：给定的值无效
 *
 * 描述
 *      此服务获取当前刻度值与先前读取的刻度值之间的刻度数。
 *
 * 引用
 *      AUTOSAR OS 8.4.19 GetElapsedValue [SWS_Os_00392]
 */
FUNC(StatusType, OS_CODE) GetElapsedValue(
	VAR(CounterType, AUTOMATIC) CounterID,
	VAR(TickRefType, AUTOMATIC) Value,
	VAR(TickRefType, AUTOMATIC) ElapsedValue)
{
	VAR(StatusType, AUTOMATIC) status;

	CONTEXT_CHECK(ENV_TASK | ENV_CAT2_ISR)

#if defined(EXTENDED_STATUS)
	/**
	 * 在扩展模式下，检查传入参数是否过大
	 *
	 * [SWS_Os_00381]
	 * ⌈如果GetElapsedValue ()调用中的
	 * 输入参数 <CounterID>无效，
	 * 则GetElapsedValue () 应返回E_OS_ID 。 ⌋ ( )
	 */
	if (CounterID >= AUTOSAR_NR_COUNTER) {
		status = E_OS_ID;
		goto out;
	}

	/**
	 * 在拓展模式下，检查传入的引用是否为 NULL
	 *
	 * [SWS_Os_00566]
	 * ⌈操作系统 API 应在扩展模式下检查所有指针参数
	 * 是否为NULL指针，如果此类参数为NULL ，
	 * 则以扩展状态返回E_OS_PARAM_POINTER 。 ⌋ ( )
	 */
	if (Value == NULL || ElapsedValue == NULL) {
		status = E_OS_PARAM_POINTER;
		goto out;
	}

	/**
	 * 在拓展模式下，检查传入的value值是否超出有效范围
	 *
	 * [SWS_Os_00391]
	 * ⌈如果GetElapsedValue ()调用中的
	 *  <Value>大于 <CounterID> 的最大允许值，
	 * GetElapsedValue () 应返回E_OS_VALUE。 ⌋ ( )
	 */
	if (*Value > autosar_counters[CounterID].max_value) {
		status = E_OS_VALUE;
		goto out;
	}
#endif

	/****************************************
	 * [SWS_Os_00533]
	 * ⌈ GetElapsedValue ()注意事项：
	 * 如果定时器已经通过<Value>值一秒（或多次）时间，
	 * 返回的结果是错误。
	 * 原因是服务无法检测到这样的相对溢出。 ⌋ ( )
	 * [SWS_Os_00534]
	 * ⌈ GetElapsedValue ()的可用性：
	 * 可用于所有可扩展性类。 ⌋ ( )
	 ***************************************/

	/**
	 * [SWS_Os_00382]
	 * ⌈如果GetElapsedValue ()调用中的输入参数有效，
	 * GetElapsedValue()应通过 <ElapsedValue>
	 * 返回自给定 <Value> 值以来经过的tick数，
	 * 并应返回E_OK。 ⌋ ( SRS_Frt_00034 )
	 *
	 * [SWS_Os_00460]
	 * ⌈ GetElapsedValue () 应在 <Value> 参数中
	 * 返回计数器的当前刻度值。 ⌋ ( )
	 */
	status = __get_elapsed_value(CounterID, Value, ElapsedValue);

out:
	return status;
}
